3.1 设计复杂的iOS动画效果
3.1.1 制定统一的动画接口
说明:制定统一的动画接口有如下优点
- 便于实现后续复杂的动画组合
- 对于后续的代码维护极为方便
- 需要优先考虑里氏代换原则
3.1.2 动画中的高内聚低耦合原理
说明:将视图的动画效果的实现和视图本身封装到另一个
UIView
中。
技巧:
- 不要把实现动画的细节暴露在外
- 设计动画类尽力那个要符合
单一职能原则
,以便后续方便组合成复杂的动画效果单一职能原则:如果一个类承担的只能过多,就等于把这些功能耦合在一起,一个职能的变化可能会削弱或者抑制其他职能的能力,这种耦合会导致脆弱的设计,当发生变化时,设计会遭到意想不到的破坏。如果想要避免这种现象发生,就要尽可能的遵守
单一职能原则
。
LineView.h
1 |
|
LineView.m
1 |
|
viewcntroller.m
1 |
|
3.1.3 设计动画函数的注意事项
- 动画方法的命名统一:封装在不同的
view
的同类动画方法命名要一致 - 预留非动画情形的设计:避免
TableView
或者其它存在重用问题的场景下的性能问题 - 用百分比来表示动画的执行程度
- 懒加载的使用
案例
LineUIView.h
1 |
|
LineUIView.m
1 |
|
ViewController.m
1 |
|
3.1.4 用里氏代换原则来处理动画类的继承问题
说明:其实就是利用对象的
多态性
,父类变量动态调用子类对象的方法。
要点:
- 里氏代换原则的基本原理
- 设计中要确保父类可以直接调用子类的方法
- 将父类设计成虚类(需要时,父类也可以提供实现)
3.1.4.1 父类
SuperUIView.h
1 | #import <UIKit/UIKit.h> |
SuperUIView.m
1 |
|
3.1.4.2 子类
说明:在子类中重写集成来的
show
的hide
方法。
SubUIView1.m
1 |
|
SubUIView2.m
1 |
|
3.1.4.3 演示
ViewController.m
1 | // 演示类的多态性 |
3.1.5 动画中的模块化设计
说明:模块化设计在开发中非常重要,拆分成小颗粒的模块非常便于代码的维护
要点:
- 动画效果实现难度的判断
- 将看到的动画效果查分成小模块
- 将写好的小模块组合成你所需要的动画效果
3.1.5.1 子模块
LineUIView.h、CircleUIView.h、RectUIView.h
1 | ... |
LineUIView.m、CircleUIView.m、RectUIView.m
1 | ... |
3.1.5.2 组合使用
BaseAnimationView.h
1 |
|
BaseAnimationView.m
1 |
|
3.2 iOS模糊效果的使用
背景:在项目开发中,使用模糊效果或许是很多开发者并不愿意接触的东西,因为大部分都是从开源代码里获取到的代码片段,并不一定理解别人的设计思路,此时要最大程度的修改来符合自己的项目需求并不容易。本课程我将会带领大家来定制出自己需要的模糊效果,理解设计的原理,并根据不同的需求设计出符合我们期望的效果。
要点:
- CoreImage 中的模糊滤镜
- UIImage+ImageEffects 的 category 模糊效果
- iOS8 中 UIVisualEffectView 模糊效果的使用
- 设计下载图片后自动模糊的控件
3.2.1 CoreImage中的模糊滤镜
要点:
CoreImage
是苹果用来简化图片处理的框架CIImage
、CIFilter
与CIContext
三者之间的联系CIGaussianBlur
中可以设置的参数
1 | // 1. 原始图片 |
3.2.2 UIImage + ImageEffects的category模糊效果
说明:苹果官方提供了一段无论是性能还是效果都更优的实现图片模糊效果的代码。在此基础上封装的库在以下地址可以拿到
https://github.com/YouXianMing/UIImageBlur
- 性能更好
- 可以局部模糊
- 更加易用
1 |
|
3.2.3 iOS8种UIVisualEffectView模糊效果的使用
说明:
UIVisyalEffectView
的模糊效果是即时渲染的,效率非常高
注意:在UIVisualEffectView
之上的文本显示需要特殊处理
兼容性:iOS8+
案例:
1 | /*--- 1. 环境 ----*/ |
3.2.4 设计下载图片后自动模糊的控件
说明:将下载下来的图片自动模糊的控件。
要点:
- KVO监听下载完成后的事件
- 在子线程中进行渲染,主线程中进行图片的下载 (提升性能)
3.2.4.1 控件实现
依赖:
GDC
和UIImage+ImageEffects
BlurDownloadPicView.h
1 |
|
BlurDownloadPicView.m
1 |
|
3.2.4.2 使用
ViewController.m
1 |
|
3.3 使用 maskView 设计动画
3.3.1 maskView(maskLayer)的基本原理
说明:本课时主要讲解
maskView(maskLayer)
的基本原理,并用示例演示。
1 | CGFloat width = 120; |
3.3.2 maskView配合 CAGradientLayer的使用
说明:本课时讲解如何在 maskView 中加载
CAGradientLayer
。要点:
- 用
CAGradientLayer
直接产生带透明像素通道的layer
- 用
maskView
直接加载带CAGradientLayer
的View
- 可以通过
CAGradientLayer
进行动画的操作实现动画效果
1 | // 1. 底图 |
3.3.3 maskView 配合带 alpha 通道图片的使用
说明:本课时讲解
maskView
加载png
图片的原理。
- 直接使用带
alpha
通道的png
图片比用CAGradientLayer
的方式更加高效- 可以使用技巧在
maskView
上添加多张图片- 在
maskView
中做简单的动画
1 | // 遮罩图片1 |
3.3.4 设计文本横向渐变消失的控件
说明:本课时将综合前面所学内容设计一个效果不错的文本渐变消失的控件,并做简易的扩展设计。
- 接口的设计
- 封装
CAGradientLayer
用以提供mask
遮罩- 动画样式的分析与设计
3.3.4.1 文本横向渐变消失的控件
FadeStrinUIView.h
1 |
|
FadeStringUIView.m
1 |
|
3.3.4.2 使用该控件
ViewController.m
1 |
|
3.4 使用 Facebook 开源动画库 POP 实现
课程说明:
POP
动画库是CoreAnimation
的实现机制有着巨大区别,但使用方式极为相似,其动画效果逼真而优美,虽无法完全替换CoreAnimation
,但掌握它,将会使你的应用的交互效果惊艳而脱颖而出。
Github地址:https://github.com/facebook/pop
3.4.1 POP
动画引擎简介
课程说明:本课时示例演示
POP
动画的强大之处,讲解CADisplayLink
的作用,以及POP
动画引擎与CoreAnimation
之间的联系。
- pop动画引擎是Facebook公司开源的
- pop动画引擎主要实现了真实物理系的动画效果(弹簧效果与衰减效果)
- pop动画引擎的动画效果非常流畅,因为它是用了
CADisplayLink
来刷新画面(帧)- pop动画引擎自成体系,与系统的
CoreAnimation
有很大的区别,但使用非常类似
3.4.1.1 POP效果展示
3.4.1.2 CADisplayLink
说明:
POP
通过CADisplayLink
刷新动画的(60帧/秒,同iOS系统本身的刷新频率)。
ViewController.m
说明:演示
CADisplayLink
使用方式,在中端1秒输出60次。
1 |
|
3.4.2 POP
动画引擎中Layer
与CALayer
的联系与区别
课程说明:本课时讲解
POP
动画中的 Layer 与CALayer
的一些共性与区别。
比较:
- 使用
POP
动画与使用CALayer
动画非常相似
POP
动画的执行没有中间状态:相比POP动画,CALayer
动画有中间状态:实际动画角色是立即到达结束时的位置的,中间状态指的是是“虚拟”的动画
POP
动画是对CALayer
动画的扩充,但不能实现所有的CALayer
的动画效果POP
动画可以作用在任何对象上,不仅仅是CALayer
其它参考:
实例:
- 导入
POP
框架(https://github.com/facebook/pop)方式1:使用cocoapods安装
方式2:直接导入源码(可以配合pch
文件)
教程:http://www.jianshu.com/p/67ce72c4ad6c
方式3:二进制文件.framework
3.4.2.1 导入POP
框架
说明:使用
CocoaPods
可能的出错:http://www.tuicool.com/articles/InIBbaf
注意:安装好依赖后,需要从项目名.xcworkspace
重启项目。
1 | $ pod search pop# 搜索版本号 |
3.4.2.1 比较CALayer和POP CAlayer
ViewController.m
1 |
|
3.4.3 用POP
动画引擎实现衰减动画
课程说明:本课时用
POP
动画引擎实现移动View
并停止时衰减的动画效果。
要点:
- 衰减动画由
POPDecayAnimation
来实现- 需要精确计算停止运动瞬间的加速度才能用衰减动画做出真实的效果
ViewController.m
1 |
|
3.4.4 用POP
动画引擎实现弹簧动画
课程说明:本课时用
POP
动画引擎实现 View 的放大缩小等的弹簧效果。
扩展:Shimmer
要点:
- 弹簧动画由
POPSpringAnimation
- 弹簧的质量、速度、时间等值都是可以设置的
1 |
|
3.5 用缓动函数模拟物理动画
3.5.1 缓动函数简介
课程说明:本课时将演示缓动函数能做出来的效果,然后讲解它的基本原理。
- 缓动函数的动画效果是建立在
CALayer
层级的关键帧动画基础之上- 缓动函数是一系列模拟物理效果(如抛物线)方程式的统称,用以计算给定亮点之间的插值
- 两点之间插的值越多,效果越好,但是会耗费更多的性能
- 只有理解了缓动函数的原理才有可能写出自己想要的效果
3.5.1.1 缓动函数类型
3.5.1.2 缓动效果示例
3.5.2 缓动函数与关键帧动画的联系
课程说明:本课时将讲解关键帧动画的原理,并分析关键帧动画与缓动函数之间的联系。
- 关键帧动画需要提供很多的帧来完善动画效果
- 关键帧动画的帧可以通过一定的数学计算来提供需要的帧数
关键帧动画只需要提供起始点、结束点,就可以通过缓动函数来计算中间“缺失”的帧
- 缓动函数可以指定计算出多少帧
- 帧数越多,动画越流畅,但同时耗费更多GPU性能
注意:
- 缓动动画只是缓动函数在关键帧动画中的一种应用
- 当只插值只有起点和终点时,关键帧动画和基本动画效果一致
1 |
|
3.5.3 用缓动函数模拟弹簧效果
课程说明:本课时用缓动函数结合关键帧动画实现弹簧效果,并模拟秒表摆动效果。
1 |
|
3.5.4 用缓动函数模拟碰撞效果
课程说明:本课时用缓动函数实现碰撞动画效果,并分析用途。
- 使用
easeOutBounce
函数来创建碰撞效果- 将
easeOutBounce
创建出来的帧数组添加到关键帧动画中- 碰撞效果用途
1 |
|
3.5.5 用缓动函数模拟衰减效果
课程说明:本课时用缓动函数实现衰减动画效果,并分析用途。
- 使用
easeOutCubic
函数来创建弹簧效果- 将
easeOutCubic
创建出来的的帧数组添加到关键帧动画中- 衰减效果用途
1 |
|
3.6 使用带粒子效果的 CAEmitterLayer
3.6.1 用 CAEmitterLayer 产生粒子效果
课程说明:本课时讲解
CAEmitterLayer
的一些基本属性,以及基本的用法。
CAEmitterLayer
的用途:实现粒子效果CAEmitterLayer
参数CAEmitterLayer
优点:使用GPU
渲染,不占用CPU
资源,远优于使用大量的随机View
来实现。
1 | // 1. CAEmitterLayer |
3.6.2 封装 CAEmitterLayerUIVIew
课程说明:本课时讲解了为了避免繁琐的设置而将
CAEmitterLayer
封装成一个较为通用的父类供子类使用。
- 替换
CAEmitterLayer
成UIView
子类的backedLayer
- 将
CAEmitterLayer
封装的类作为“抽象“父类说明:封装一个父类(
CAEmitterLayerUIView
),其它类型的粒子图层继承该类,将设置封装到子类的show
和hide
实现中。
CAEmitterLayerUIView.h
1 |
|
CAEmitterLayerUIView.m
1 |
|
3.6.3 封装下雪、下雨的粒子效果控件
课程说明:本课时在封装
CAEmitterLayer
基础上进一步从“抽象”父类派生出下雪、下雨的子类控件。
- 从封装
CAEmitterLayer
的“抽象”父类继承的原因- 下雪、下雨效果参数的设置
ViewController.m
说明:使用控件
1 | // 1. 初始化粒子效果图层 |
3.7 iOS 中 CAGradientLaueyer 的使用
3.7.1 CAGradientLayer 简介
课程说明:本课演示
CAGradientLayer
能做的一些动画效果,以及CAGradientLayer
与CAShapeLayer
配合使用的实例。
CAGradientLayer
是用于处理渐变色的层结构CAGradientLayer
的渐变色可以做隐式动画- 大部分情况下,
CAGradientLayer
都是与CAShapeLayer
配合使用的CAGradientLayer
可以用作png
遮罩效果
CAShapeLayer
作为CAGradientLayer
的遮罩实现的效果
旋转CAGradientLayer
实现的效果
色差动画效果
作为png
图片遮罩动画效果
3.7.2 CAGradientLayer 坐标系统
课程说明:本课讲解 CAGradientLayer 的坐标系统,并延伸讲解了坐标系统影响如何颜色分配、动画效果。
CAGradientLayer
的坐标系统是从坐标(0, 0)到(1, 1)绘制的矩形CAGradientLayer
的frame
值的size
不为正方形的话,坐标系统会被拉伸CAGradientLayer
的startPoint
与endPoint
会直接影响颜色的绘制方向CAGradientLayer
的颜色分割线是以0到1的比例来计算的
1 |
|
3.7.3 色差动画的实现
课程说明:本课用 CAGradientLayer 实现色差动画效果。
- 确定渐变色渐变方向
- 设定两种颜色,其中一种是透明色,另外一种是自定义颜色
- 设定好
location
颜色分割点CAGradientLayer
的颜色分割点是0到1的比例来计算的
1 |
|
3.7.4 用 CAGradientLayer 封装带色差动画的 View
课程说明:本课讲解将色差动画效果封装到 View 当中。
- 确定几个属性值
- 去定意义做动画的参数
- 重写
setter
做动画
3.7.4.1 封装好的视图
说明:将对视图的渐变层的设置工作整合到
setter
中。
ColorUIImageView.h
1 |
|
ColorUIImageView.m
1 |
|
3.7.4.2 使用
ViewController.m
1 |
|
3.8 iOS中 CAShapeLayer 的使用
3.8.1 CAShapeLayer 简介
课程说明:本课介绍
CAShapeLayer
与CALayer
、贝塞尔曲线之间的简单联系,并通过一个 demo 演示CAShapeLayer
实现的路径动画效果。
CAShapeLayer
继承自CALayer
,可以使用CALayer
的所有属性值CAShapeLayer
需要与贝塞尔曲线配合使用才有意义- 使用
CAShapeLayer
与贝塞尔曲线可以实现不在view
的drawRect
方法中画出一些想要的图形CAShapeLayer
属于CoreAnimation
框架,其动画渲染直接提交到手机的GPU
当中,相较于view
的srawRect
方法使用CPU
渲染而言,其效率极高,能大大优化内存使用情况。
3.8.2 贝塞尔曲线与 CAShapeLayer 的关系
课程说明:本课介绍多阶贝塞尔曲线的用途,并详细讲解贝塞尔曲线与
CAShapeLayer
之间的关系,以及使用贝塞尔曲线的一些注意事项。
CAShapeLayer
中有Shape
这个单词,顾名思义,它需要一个形状才能生效- 贝赛尔曲线可以创建基于矢量的路径
- 贝塞尔曲线给
CAShaperLayer
提供路径,CAShpaeLayer
在提供的路径中进行渲染,路径会闭环,所以路径绘制出了Shape
- 用于
CAShapeLayer
的贝赛尔曲线作为path
,其中path
是一个首尾相接的闭环的曲线,即使该贝赛尔曲线不是一个闭环的曲线。
ViewCnotroller.m
1 |
|
3.8.3 StrokeStart 与 StrokeEnd 动画
课程说明:本课讲解如何设置
CAShapeLayer
的属性值来显示出圆环并用CAShapeLayer
的StrokeStart
与StrokeEnd
属性做动画。
- 将
ShapeLayer
的fillColor
设置成透明背景- 设置线条的宽度(
lineWidth
)的值- 设置线条的颜色
- 将
strokeStart
的值设定成0,然后让strokeEnd
的值变化触发隐式动画注意:同时设置
strokeStart
和strokeEnd
时,前者不能大于后者。
1 |
|
3.8.4 用 CAShapeLayer 实现圆形进度条效果
课程说明:本课在课时 3 的基础上将动画效果封装到控件当中。
- 确定需要设定的参数
- 实现细节
- 进行测试
3.8.4.1 圆形进度条控件
CircleUIView.h
1 |
|
CircleUIView.m
1 |
|
3.8.4.2 使用
ViewController.m
1 |
|
3.9 iOS中 CALayer 的使用
3.9.1 用 CALayer 定制下载进度条控件
课程说明:本课在通过对
CALayer
的基本原理讲解后用CALayer
基本知识定制下载进度条控件。
- 单独创建出
CALayer
- 直接修改
CALayer
的frame
值执行隐式动画,实现进度条效果- 用定时器(
NSTimer
)模拟网络下载时提供的百分比数据- 将
CALayer
封装进UIView
子类中定制进度条控件CALayer简介:
CALayer
一般作为UIView
的容器使用CALayer
是一个管理着图片载体(image-based content)的 层结构- 直接修改单独创建出的
CALayer
的属性可以触发隐式动画(不需要其它设置,修改属性直接触发动画)UIView
中的CALayer
动画必须显式触发才能生效
3.9.2.1 原理
说明:直接修改
CALayer
的frame
值执行隐式动画,实现进度条效果。
1 | // 创建layer并添加layer |
3.9.1.2 实战
3.9.2 用 CALayer 定制 UIImageView 淡入淡出切换图片效果
课程说明:本课将利用动画组
CAAnimationGroup
将bounds
动画与contents
动画组合起来实现切换图片时的淡入淡出效果。
- 操作
UIImageView
的CALayer
修改其bounds
值进行显示动画- 修改
UIImageView
的CALayer
中的contents
属性实现切换图片的动画- 用
CAAnimationGroup
将bounds
动画与contents
动画组合起来- 将上述效果封装进
UIView
的子类中生成控件
3.9.2.1 封装动画效果
FadeUIView.h
1 |
|
FadeUIView.m
1 |
|
3.9.2.2 使用控件
ViewController.m
1 |
|
3.9.3 用 CALayer 实现复杂遮罩效果
课程说明:本课将利用 CALayer 的 mask 属性作为遮罩 Layer,通过移动该遮罩 Layer 的 frame 值实现复杂的遮罩效果。
- 遮罩原理分析
- 用
png
图片作为CALayer
中mask
属性的遮罩Layer
- 移动该
CALayer
的mask
的frame
值实现遮罩Layer
1 |
|
3.10 iOS绘图 API 绘制线条/文字/几何图形
3.10.1 绘制线条
DrawLines.swift
1 | import UIKit |
3.10.2 绘制矩形
DrawRectView.swift
1 | import UIKit |
3.10.3 绘制圆形
DrawCircleView.swift
1 | import UIKit |
3.10.4 绘制图片
1 | import UIKit |
3.10.5 画板实例
DrawBoardView.swift
1 | import UIKit |